package com.heakey.common.component;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.event.cache.model.NamespaceCacheKey;
import com.heakey.common.constant.CommonConstant;
import com.heakey.common.enums.CacheNameEnum;
import com.heakey.common.model.PageReq;
import com.heakey.common.model.RedisWrapper;
import com.heakey.common.redis.IRedisService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * @Description 缓存服务
 * @Author Bing
 * @Date 2025/5/16 15:15
 */
@Service
public class NameSpacePageCacheService {

    @Resource
    private IRedisService redisService;

    /**
     * 批量获取缓存值，如果缓存中没有则从数据库查询，并设置缓存
     * @param eventCacheKeys
     * @param batchList
     * @return
     * @param <T>
     */
    public <T> List<T> getByBatch(List<NamespaceCacheKey> eventCacheKeys, Function<List<String>, Map<String,T>> batchList){
        // 获取缓存有效时间
        NamespaceCacheKey firstCacheKey = eventCacheKeys.get(0);
        Long effectiveTime = CacheNameEnum.get(firstCacheKey.getPerfix()).getSeconds();
        // 构建缓存key
        Map<String,String> keysMap = buildCacheKeys(eventCacheKeys);
        // 批量获取缓存key
        List<String> keys = keysMap.values().stream().collect(Collectors.toList());
        // 批量获取缓存key对应的id
        List<String> ids = keysMap.keySet().stream().collect(Collectors.toList());

        // 批量获取缓存值
        List<RedisWrapper> values = redisService.batch(keys, RedisWrapper.class).stream().collect(Collectors.toList());
        // 缓存的结果
        List<T> cacheValues = new ArrayList<>();
        // 收集没有缓存的id
        List<String> noCacheIds = new ArrayList<>();
        for(int i = 0 ; i < values.size() ; i++){
            RedisWrapper<T> redisWrapper = values.get(i);
            // 包装类没有的那就说明缓存没有
            if(Objects.isNull(redisWrapper)){
                noCacheIds.add(ids.get(i));
                continue;
            }
            // 包装类中没有数据，说明有缓存只是没有值
            if(ObjectUtil.isNull(redisWrapper.data)){
                continue;
            }
            // 有值的加入结果中
            cacheValues.add(redisWrapper.data);
        }
        //
        if(CollUtil.isNotEmpty(noCacheIds)){
            // 缓存中没有，则从数据库查询并返回来
            Map<String,T> notCacheValues = batchList.apply(noCacheIds);
            // 批量设置缓存
            for(String id : noCacheIds){
                String cacheKey = keysMap.get(id);
                if(StrUtil.isBlank(cacheKey)){
                    continue;
                }
                // 获取数据库查询的值
                T cacheValue = notCacheValues.get(id);
                // 设置缓存
                redisService.setValue(cacheKey,new RedisWrapper<T>(cacheValue),effectiveTime.intValue());
                // 有值的加入结果中
                if(Objects.nonNull(cacheValue)){
                    cacheValues.add(cacheValue);
                }
            }
        }
        return cacheValues;
    }

    /**
     *  缓存列表(一般用于首页缓存)
     * @param namespaceCacheKey
     * @param pageList
     * @return
     * @param <T>
     */
    public <T> List<T> list(NamespaceCacheKey namespaceCacheKey, Supplier<List<T>> pageList){
        String cacheKey = namespaceCacheKey.parseAll();
        // 获取缓存的值
        List<?> list = redisService.getValue(cacheKey,List.class);
        // 缓存有直接返回
        if(Objects.nonNull(list)){
            return (List<T>) list;
        }
        // 没有则去数据库查询
        List<T> dbList = pageList.get();
        Long effectiveTime = CacheNameEnum.get(namespaceCacheKey.getPerfix()).getSeconds();
        // 设置缓存
        redisService.setValue(cacheKey,dbList,effectiveTime.intValue());
        return dbList;
    }

    /**
     * 是否是首页
     * @param pageReq
     * @return
     */
    public boolean isPageOne(PageReq pageReq){
        return pageReq.getPageNum().equals(CommonConstant.NUM_ONE);
    }

    /**
     * <id,key>构建缓存key
     * @param eventCacheKeys
     * @return
     */
    private Map<String,String> buildCacheKeys(List<NamespaceCacheKey> eventCacheKeys){
        Map<String,String> map = new HashMap<>();
        for(NamespaceCacheKey eventCacheKey : eventCacheKeys){
            map.put(eventCacheKey.getFilterValue(),eventCacheKey.parseEndOfFilter());
        }
        return map;
    }
}